package com.ccb.sc.live.service;

import cn.hutool.core.lang.UUID;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.ccb.sc.live.controller.query.LiveStreamingGoodsQueryParam;
import com.ccb.sc.live.mapper.LiveStreamingMapper;
import com.ccb.sc.live.vo.LiveStreamingGoodsGroupListVo;
import com.ccb.sc.live.vo.LiveStreamingListVo;
import com.ccb.sc.live.vo.LiveStreamingPreviewVo;
import com.ccb.sc.live.vo.LiveStreamingReserveListVo;
import com.ccb.sc.member.service.DailyTaskService;
//psl import com.ccb.sc.common.bind.exception.BizException;
import com.ccb.sc.common.bind.page.PageParams;
import com.ccb.sc.common.bind.page.PageVo;
import com.ccb.sc.common.bind.query.Filter;
import com.ccb.sc.common.code.BizCodeFace;
import com.ccb.sc.common.code.ErrorCode;
import com.ccb.sc.common.enums.ValidStatus;
import com.ccb.sc.common.modules.common.service.IRedisService;
import com.ccb.sc.common.modules.live.convert.LiveStreamingGoodsConvert;
import com.ccb.sc.common.modules.live.entity.LiveStreaming;
import com.ccb.sc.common.modules.live.entity.LiveStreamingGoods;
import com.ccb.sc.common.modules.live.entity.LiveStreamingGoodsFreebie;
import com.ccb.sc.common.modules.live.entity.LiveStreamingReserve;
import com.ccb.sc.common.modules.live.mapper.LiveStreamingGoodsFreebieMapper;
import com.ccb.sc.common.modules.live.mapper.LiveStreamingGoodsMapper;
import com.ccb.sc.common.modules.live.vo.LiveStreamingGoodsFreebieVo;
import com.ccb.sc.common.modules.live.vo.LiveStreamingGoodsListVo;
import com.ccb.sc.common.modules.member.entity.Member;
import com.ccb.sc.common.modules.member.enums.MemberPointsLogType;
import com.ccb.sc.common.modules.member.service.MemberMedalService;
import com.ccb.sc.common.modules.member.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author ken
 * @version 1.0
 * @date 2022/8/13 17:45
 */
@Service
public class LiveStreamingService extends ServiceImpl<LiveStreamingMapper, LiveStreaming> {

    @Autowired
    private LiveStreamingGoodsMapper liveStreamingGoodsMapper;

    @Autowired
    private LiveStreamingGoodsFreebieMapper liveStreamingGoodsFreebieMapper;

    @Autowired
    private AppLiveStreamingReserveService appLiveStreamingReserveService;

    @Autowired
    private DailyTaskService dailyTaskService;

    @Autowired
    private MemberService memberService;

    @Autowired
    private IRedisService redisService;

    @Autowired
    private MemberMedalService memberMedalService;

    public List<LiveStreamingListVo> selectMonthLiveStreamingList(Long memberId) {
        List<LiveStreamingListVo> result = this.getBaseMapper().selectList(memberId);
        /*List<LiveStreaming> list = this.list(Wrappers.<LiveStreaming>lambdaQuery()
                .eq(LiveStreaming::getStatus, ValidStatus.VALID)
                .orderByDesc(LiveStreaming::getLiveName));
        if (CollectionUtils.isEmpty(list)) {
            return Lists.newArrayList();
        }
        Long lastLiveId = this.getBaseMapper().selectLastLiveId();
        List<LiveStreamingListVo> result = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            LiveStreaming liveStreaming = list.get(i);
            LiveStreamingListVo liveStreamingListVo = new LiveStreamingListVo();
            liveStreamingListVo.setLiveId(liveStreaming.getId());
            liveStreamingListVo.setLiveName(liveStreaming.getLiveName());
            liveStreamingListVo.setPicture(liveStreaming.getPicture());
            liveStreamingListVo.setLiveTime(liveStreaming.getLiveTime());
            liveStreamingListVo.setLiveEndTime(liveStreaming.getLiveEndTime());
            liveStreamingListVo.setLiveTag(liveStreaming.getLiveTag());
            liveStreamingListVo.setDate(liveStreaming.getLiveTime().toLocalDate());
            if (liveStreaming.getId().equals(lastLiveId)) {
                liveStreamingListVo.setIsLast(true);
            }
            result.add(liveStreamingListVo);
        }
        if (lastLiveId == null || lastLiveId == 0) {
            result.get(0).setIsLast(true);
        }*/

        if (memberId != null) {
            this.dailyTaskService.reward(memberId, MemberPointsLogType.RAIDERS_DOCUMENT, "");
        }

        return result;
    }

    public LiveStreamingPreviewVo preview(Long memberId) {
        LiveStreaming liveStreaming = this.getOne(Wrappers.<LiveStreaming>lambdaQuery()
                .eq(LiveStreaming::getStatus, ValidStatus.VALID)
                .orderByDesc(LiveStreaming::getLiveTime)
                .last("limit 1"));
        LiveStreamingPreviewVo previewVo = new LiveStreamingPreviewVo();
        if (liveStreaming != null) {
            previewVo.setLiveId(liveStreaming.getId());
            previewVo.setArticleUrl(liveStreaming.getArticleUrl());
            previewVo.setLiveTime(liveStreaming.getLiveTime());
            previewVo.setLiveEndTime(liveStreaming.getLiveEndTime());
            if (memberId != null) {
                long count = this.appLiveStreamingReserveService.count(Wrappers.<LiveStreamingReserve>lambdaQuery()
                        .eq(LiveStreamingReserve::getMemberId, memberId)
                        .eq(LiveStreamingReserve::getLiveId, liveStreaming.getId()));
                previewVo.setReserve(count > 0);
            }else {
                previewVo.setReserve(false);
            }
        }
        return previewVo;
    }

    public List<LiveStreamingGoodsGroupListVo> findLiveStreamingGoodsList(Long memberId, LiveStreamingGoodsQueryParam queryParam) {
        Assert.notNull(queryParam.getLiveId(), "直播id不能为空");
        LiveStreamingGoodsMapper.QueryParam params = new LiveStreamingGoodsMapper.QueryParam();
        params.setLiveId(queryParam.getLiveId());
        params.setGoodsName(Filter.LikeValue.both(queryParam.getGoodsName()));
        params.setCategoryId(queryParam.getCategoryId());
        params.setOfferCategory(queryParam.getOfferCategory());
        params.setMemberId(memberId);
        if (queryParam.getCrossStoreFullReduction() != null) {
            params.setCrossStoreFullReduction(queryParam.getCrossStoreFullReduction() == 1);
        }
        List<LiveStreamingGoodsListVo> list = this.liveStreamingGoodsMapper.selectListByLiveId(params);
        if (CollectionUtils.isEmpty(list)) {
            return Lists.newArrayList();
        }
        List<LiveStreamingGoodsGroupListVo> result = new ArrayList<>();
        List<Long> goodsIds = list.stream().map(LiveStreamingGoodsListVo::getId).collect(Collectors.toList());
        List<LiveStreamingGoodsFreebie> goodsFreebies = this.liveStreamingGoodsFreebieMapper.selectList(Wrappers.<LiveStreamingGoodsFreebie>lambdaQuery()
                .in(LiveStreamingGoodsFreebie::getLiveStreamingGoodsId, goodsIds));
        if (!CollectionUtils.isEmpty(goodsFreebies)) {
            Map<Long, List<LiveStreamingGoodsFreebieVo>> goodsFreebieVoMap = goodsFreebies.stream().
                    map(LiveStreamingGoodsConvert.INSTANCE::itemEntity2Vo).collect(Collectors.groupingBy(LiveStreamingGoodsFreebieVo::getLiveStreamingGoodsId));
            for (LiveStreamingGoodsListVo liveStreamingGoodsListVo : list) {
                liveStreamingGoodsListVo.setFreebieGoods(goodsFreebieVoMap.get(liveStreamingGoodsListVo.getId()));
            }
        }
        Map<String, List<LiveStreamingGoodsListVo>> categoryGoodsListMap = list.stream().collect(Collectors.groupingBy(LiveStreamingGoodsListVo::getCategoryName));
        for (Map.Entry<String, List<LiveStreamingGoodsListVo>> entry : categoryGoodsListMap.entrySet()) {
            LiveStreamingGoodsGroupListVo liveStreamingGoodsGroupListVo = new LiveStreamingGoodsGroupListVo();
            liveStreamingGoodsGroupListVo.setCategoryName(entry.getKey());
            liveStreamingGoodsGroupListVo.setGoodsList(entry.getValue());
            result.add(liveStreamingGoodsGroupListVo);
        }
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    public void reserve(Long memberId, Long liveId, Long liveStreamingGoodsId) {
        String redisKey = String.format("lock:reserve:%s", memberId);
        String randomStr = UUID.randomUUID().toString();
        try {
            boolean lock = this.redisService.lock(redisKey, randomStr, 5);
            if (!lock) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAST_FREQUENCY));
            }
            LambdaQueryWrapper<LiveStreamingReserve> queryWrapper = Wrappers.<LiveStreamingReserve>lambdaQuery()
                    .eq(LiveStreamingReserve::getLiveId, liveId)
                    .eq(LiveStreamingReserve::getMemberId, memberId);

            if (liveStreamingGoodsId != null) {
                // 增加商品预约总人数
                LiveStreamingGoods liveStreamingGoods = this.liveStreamingGoodsMapper.selectById(liveStreamingGoodsId);
                Assert.notNull(liveStreamingGoods, "直播商品不存在！");
                liveStreamingGoods.setReservations(liveStreamingGoods.getReservations() + 1);
                this.liveStreamingGoodsMapper.updateById(liveStreamingGoods);
                queryWrapper.eq(LiveStreamingReserve::getLiveStreamingGoodsId, liveStreamingGoodsId);
            }

            long count = this.appLiveStreamingReserveService.count(queryWrapper);
            if (count > 0) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.DATE_NULL).message("您已预约，请勿重复预约"));
            }

            // 增加直播预约总人数
            LiveStreaming liveStreaming = this.getById(liveId);
            Assert.notNull(liveStreaming, "直播不存在！");
            Assert.isTrue(liveStreaming.getLiveEndTime().isAfter(LocalDateTime.now()), "直播已结束");
            liveStreaming.setReservations(liveStreaming.getReservations() + 1);
            this.updateById(liveStreaming);
            // 增加直播预约记录
            LiveStreamingReserve liveStreamingReserve = new LiveStreamingReserve();
            Member member = this.memberService.getById(memberId);
            liveStreamingReserve.setMemberId(memberId);
            liveStreamingReserve.setOpenId(member.getOauthId());
            liveStreamingReserve.setLiveId(liveStreaming.getId());
            liveStreamingReserve.setLiveStreamingGoodsId(liveStreamingGoodsId);
            liveStreamingReserve.setStatus(0);
            this.appLiveStreamingReserveService.save(liveStreamingReserve);

            // 每日奖励
            this.dailyTaskService.reward(memberId, MemberPointsLogType.RESERVE, "");

            // 执行规则校验勋章
            this.memberMedalService.executeRule(memberId);
        }finally {
            boolean unLock = this.redisService.unLock(redisKey, randomStr);
            if (!unLock) {
                this.redisService.unLock(redisKey, randomStr);
            }
        }
    }

    public PageVo<LiveStreamingReserveListVo> reserveList(Long memberId, PageParams queryParam) {
        Page<LiveStreamingReserve> page = new Page<>(queryParam.getCurrent(), queryParam.getPageSize());
        Page<LiveStreamingReserveListVo> reservePage = this.appLiveStreamingReserveService.getBaseMapper().selectByQueryParam(page, memberId);
        return PageVo.create(queryParam.getCurrent(), queryParam.getPageSize(), reservePage.getTotal(), reservePage.getRecords());
    }
}
